#!/usr/bin/env python

import cgi, cgitb

cgitb.enable(display=1, format='txt')

#print "Content-Type: text/plain\n"

chunk_size = 1048576 #1MB chunk size
share_path='shared/'

class Client:
	"""The Client class. Includes methods and attributes to ease communication with clients."""

	def say(self, msg):
		"""Send a msg to the client."""
		import json

		print "Content-Type: text/plain\n"
		print json.dumps(msg)

def send_reply(client, type, value):
	"""Encapsulates a message type with a value and sends it to the client."""
	reply = { 'type':type, 'value':value } 
	client.say(reply)


def list_files(rootdir, unroot=False):
	"""Returns a dictionary of files in rootdir. Setting unroot to True strips the rootdir from its entries"""
  	import os, re
	fileList = []
	i = 0
	for root, dirs, files in os.walk(rootdir):
		for file in files:
			full_path = os.path.join(root, file)
			file_size = os.path.getsize(full_path)
			if unroot:
				full_path = re.sub(r'%s/*' % rootdir, '', full_path)
				fileList.append((i, (full_path, file_size, chunk_list(file_size)[0])))
			else:
				fileList.append((i, (full_path, file_size, chunk_list(file_size)[0])))
			i += 1

	return dict(fileList)

def chunk_list(file_size):
	"""Calculates the number of possible chunks for a given file_size"""
	list = [chunk_size] * (file_size / chunk_size)
	if file_size%chunk_size > 0:
		list.append((file_size % chunk_size))

	return len(list), list

def file_chunk(file_id, chunk_number):
	"""Searches for file_id in the file list and returns a tuple with
	the chunk_number, a base64 encoded file chunk and its crc32 checksum."""
	import base64, os, binascii

	(file_name, file_size, _) = list_files(share_path)[file_id]

	list_size, list = chunk_list(file_size)

	if chunk_number >= list_size:
		return None

	f = open(file_name, 'r')
	f.seek(chunk_size*chunk_number)
	buff = f.read(list[chunk_number])
	f.close()

	return (chunk_number, base64.b64encode(buff), binascii.crc32(buff) & 0xffffffff)

if __name__ == '__main__':
	form = cgi.FieldStorage()
	client = Client()

	if (client is not None) and  form.has_key("request"):
		if form['request'].value == 'LIST':
			send_reply(client, 'LIST', list_files(share_path, unroot=True))

		if form['request'].value == 'FILE' and form.has_key('args'):
			args = form.getlist('args')
			if len(args) == 2:
				send_reply(client, 'FILE', file_chunk(int(args[0]), int(args[1])))

	else:
		print 'GO AWAY'

